<?php

require_once('Adept/Template/IObserver.php');

class Adept_Template_Builder_ComponentTree implements Adept_Template_IObserver
{

    protected $root;
    /**
     * @var Adept_Template_Node
     */
    protected $current;
    
    /**
     * @var Adept_Template_Dictionary
     */
    protected $dictionary;
    
    public function __construct() 
    {
    	$this->root = new Adept_Template_RootNode();
    	$this->current = $this->root;
    	
    	$this->dictionary = Adept_Template_Dictionary::getInstance();
    }	
    
    public function comment($parser, $comment)
    {
    }

    public function processingInstruction($parser, $instruction, $parameters)
    {
        $instruction = strtoupper($instruction);
        
        if ($instruction == 'IMPORT') {
            $this->dictionary->importLibrary($parameters);
        }
    }

    public function startElement($parser, $tag, $attributes, $closed)
    {
        $tag = strtolower($tag);
        
        $info = $this->dictionary->getTagInfo($tag);
        if ($info == null) {
            throw new Adept_Template_Exception("Tag '{$tag}' not declared", array(), $parser->getLocation());
        }
        $class = $info->getClass();
        
        $tagInstance = new $class();
        $tagInstance->setName($tag);
        $tagInstance->setTagInfo($info);
        $tagInstance->setAttributes($attributes);   
        $tagInstance->setLocation(clone $parser->getLocation());
        
        $this->current->addChild($tagInstance);
        
        if (!$closed && $info->getHasClosingTag()) {
            $this->current = $tagInstance;
        }
    }

    public function endElement($parser, $tag)
    {
        $tag = strtolower($tag);
        if ($this->current->getName() != $tag) {
            throw new Adept_Template_Exception("Invalid closing tag. "
                . " '{$this->current->getName()}' wanted, but '{$tag}' founded. ", 
                array('Founded' => $tag, 'Wanted' => $this->current->getName()), clone $parser->getLocation());
        }
        $this->current = $this->current->getParent();
    }

    public function characters($parser, $charasters)
    {
        $node = new Adept_Template_Component_TextNode();
        $node->setText($charasters);
        
        $this->current->addChild($node);
    }

    public function expression($parser, $expression)
    {
        $node = new Adept_Template_Component_ExpressionNode();
        
        $node->setExpression($expression->makeExpression());
        
        $this->current->addChild($node);        
    }
    
    public function getRoot() 
    {
        return $this->root;
    }
    
    public function setRoot($root) 
    {
        $this->root = $root;
        $this->current = $this->root;
    }

}
